package zelix.hack.hacks;


import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.input.Mouse;
import zelix.hack.Hack;
import zelix.hack.HackCategory;
import zelix.utils.Utils;
import zelix.utils.ValidUtils;
import zelix.utils.Wrapper;
import zelix.value.BooleanValue;
import zelix.value.Mode;
import zelix.value.ModeValue;
import zelix.value.NumberValue;

import java.util.concurrent.ThreadLocalRandom;

public class AimAssist extends Hack {
   public static Minecraft mc = Minecraft.getMinecraft();
   public static NumberValue speed, compliment;
   public static NumberValue fov;
   public static NumberValue distance,extradistance;
   public static ModeValue priority;
   public static BooleanValue clickAim;
   public static BooleanValue weaponOnly;
   public static BooleanValue breakBlocks;
   public static BooleanValue blatantMode;
   public static BooleanValue walls;
   public EntityLivingBase target;
   public AimAssist() {
      super("AimAssist", HackCategory.COMBAT);

      this.addValue(priority = new ModeValue("Priority", new Mode("Closest", true), new Mode("Health", false)));
      this.addValue(speed = new NumberValue("Speed 1", 45.0D, 5.0D, 100.0D));
      this.addValue(compliment = new NumberValue("Speed 2", 15.0D, 2D, 97.0D));
      this.addValue(fov = new NumberValue("FOV", 90.0D, 15.0D, 360.0D));
      this.addValue(distance = new NumberValue("Distance", 4.5D, 1.0D, 10.0D));
      this.addValue(extradistance = new NumberValue("Extra-Distance", 0D, 0D, 100D));
      this.addValue(clickAim = new BooleanValue("ClickAim", true));
      this.addValue(walls = new BooleanValue("ThroughWalls", false));
      this.addValue(breakBlocks = new BooleanValue("Break blocks", true));
      //this.addValue(ignoreFriends = new BooleanValue("Ignore Friends", true));
      this.addValue(weaponOnly = new BooleanValue("Weapon only", false));
      //this.addValue(aimInvis = new BooleanValue("Aim invis", false));
      this.addValue(blatantMode = new BooleanValue("Blatant mode", false));
   }

   @Override
   public void onClientTick(TickEvent.ClientTickEvent event) {
      getTarget();


      if (breakBlocks.getValue() && mc.objectMouseOver != null) {
         BlockPos p = mc.objectMouseOver.getBlockPos();
         if (p != null) {
            Block bl = mc.world.getBlockState(p).getBlock();
            if (bl != Blocks.AIR && !(bl instanceof BlockLiquid) && bl instanceof  Block) {
               return;
            }
         }
      }


      if (!weaponOnly.getValue() || Utils.isPlayerHoldingWeapon()) {

         //Module autoClicker = Raven.moduleManager.getModuleByClazz(RightClicker.class);
         //what if player clicking but mouse not down ????
         if (clickAim.getValue() ) {
            if (Mouse.isButtonDown(0)){
               if (target != null) {

                  if (blatantMode.getValue()) {
                     Utils.Player.aim(target, 0.0F, false);
                  } else {
                     double n = Utils.Player.fovFromEntity(target);
                     if (n > 1.0D || n < -1.0D) {
                        double complimentSpeed = n*(ThreadLocalRandom.current().nextDouble(compliment.getValue() - 1.47328, compliment.getValue() + 2.48293)/100);
                        double val2 = complimentSpeed + ThreadLocalRandom.current().nextDouble(speed.getValue() - 4.723847, speed.getValue());
                        float val = (float)(-(complimentSpeed + n / (101.0D - (float)ThreadLocalRandom.current().nextDouble(speed.getValue() - 4.723847, speed.getValue()))));
                        mc.player.rotationYaw += val;
                     }
                  }


               }
            }
         }else{
            if (target != null) {

               if (blatantMode.getValue()) {
                  Utils.Player.aim(target, 0.0F, false);
               } else {
                  double n = Utils.Player.fovFromEntity(target);
                  if (n > 1.0D || n < -1.0D) {
                     double complimentSpeed = n*(ThreadLocalRandom.current().nextDouble(compliment.getValue() - 1.47328, compliment.getValue() + 2.48293)/100);
                     double val2 = complimentSpeed + ThreadLocalRandom.current().nextDouble(speed.getValue() - 4.723847, speed.getValue());
                     float val = (float)(-(complimentSpeed + n / (101.0D - (float)ThreadLocalRandom.current().nextDouble(speed.getValue() - 4.723847, speed.getValue()))));
                     mc.player.rotationYaw += val;
                  }
               }


            }
         }
      }
      target = null;
   }

   public void getTarget() {
      for (Object object : Utils.getEntityList()) {
         if (!(object instanceof EntityLivingBase)) continue;
         EntityLivingBase entity = (EntityLivingBase) object;
         if (!check(entity)) continue;
         this.target = entity;;
      }

   }

   public boolean check(EntityLivingBase entity) {
      if(entity instanceof EntityArmorStand) { return false; }
      if(ValidUtils.isValidEntity(entity)){ return false; }
      if(!ValidUtils.isNoScreen()) { return false; }
      if(entity == Wrapper.INSTANCE.player()) { return false; }
      if(entity.isDead) { return false; }
      if(ValidUtils.isBot(entity)) { return false; }
      if(!ValidUtils.isFriendEnemy(entity)) { return false; }
      if(!ValidUtils.isInvisible(entity)) { return false; }
      if(!ValidUtils.isInAttackFOV(entity, fov.getValue().intValue())) { return false; }
      if(!ValidUtils.isInAttackRange(entity, distance.getValue().floatValue()+extradistance.getValue().floatValue())) { return false; }
      if(!ValidUtils.isTeam(entity)) { return false; }
      if(!ValidUtils.pingCheck(entity)) { return false; }
      if(!isPriority(entity)) { return false; }
      if(!this.walls.getValue()) { if(!Wrapper.INSTANCE.player().canEntityBeSeen(entity)) { return false; } }
      return true;
   }

   boolean isPriority(EntityLivingBase entity) {
      return priority.getMode("Closest").isToggled() && ValidUtils.isClosest(entity, target)
              || priority.getMode("Health").isToggled() && ValidUtils.isLowHealth(entity, target);
   }
}
